/*******************************************************************************
 * Witz - Winboard Chess Engine                                                *
 * BOARD.C                                                                     *
 *                                                                             *
 * Implements most of the board structure                                      *
 *                                                                             *
 * Please refer to the licence notice in MAIN.C                                *
 *                                                                             *
 * Copywright (C) 2006 Pradu Kannan                                            *
 * http://witz.sf.net/                                                         *
 ******************************************************************************/

#include "build.h"
#include "defs.h"
#include "protos.h"
#include "data.h"

board newBoard;                      //The initial Position
board mainboard;                     //The main board
//board searchHistory[MAX_PLY];      //A history of board positions during search
int depth;                           //The current search depth
board gameHistory[MAX_GAMELENGTH];   //A history of the game
U16 gamedepth;                       //The current game move number
int compside;                        //The side that the computer plays
bool useBook;                        //Should the engine try to use the book
//This is used when gamedepth overflows over the MAX_GAMELENGTH limit
U16 initialMoveNumber;

/*initializeBoard()
 *initializes the game board
 */
void initializeBoard()
{
	mainboard.side=WHITE;
	mainboard.PiecesSide[WHITE]=0x000000000000FFFFULL;
	mainboard.PiecesSide[BLACK]=0xFFFF000000000000ULL;
	mainboard.Pieces[P]=0x00FF00000000FF00ULL;
	mainboard.Pieces[N]=0x4200000000000042ULL;
	mainboard.Pieces[B]=0x2400000000000024ULL;
	mainboard.Pieces[R]=0x8100000000000081ULL;
	mainboard.Pieces[Q]=0x0800000000000008ULL;
	mainboard.Pieces[K]=0x1000000000000010ULL;
	mainboard.EP=U64EMPTY;
	mainboard.castling=0xF;
	mainboard.fifty=0;
	mainboard.material=0;
	depth=gamedepth=0;
	compside=BLACK;
	initialMoveNumber=1;
	inferRestOfBoard();
	useBook=true;
}

/*nullBoard()
 *makes the game board null
 */
void nullBoard()
{
	mainboard.PiecesSide[WHITE]=U64EMPTY;
	mainboard.PiecesSide[BLACK]=U64EMPTY;
	mainboard.Pieces[P]=U64EMPTY;
	mainboard.Pieces[N]=U64EMPTY;
	mainboard.Pieces[B]=U64EMPTY;
	mainboard.Pieces[R]=U64EMPTY;
	mainboard.Pieces[Q]=U64EMPTY;
	mainboard.Pieces[K]=U64EMPTY;
	mainboard.side=WHITE;
	mainboard.EP=U64EMPTY;
	mainboard.castling=0;
	mainboard.fifty=0;
	mainboard.material=0;
	compside=NOSIDE;
	initialMoveNumber=1;
	inferRestOfBoard();
}

/*inferRestOfBoard()
 *infers the rest of the board (xside,R45,L45,L90,hashkey,material)
 */
void inferRestOfBoard()
{
	U64 i;
	mainboard.hashkey=U64EMPTY; //the first position has a zero key
	mainboard.xside=!mainboard.side;
	mainboard.AllPieces=mainboard.PiecesSide[WHITE]|mainboard.PiecesSide[BLACK];
	mainboard.R45=mainboard.L45=mainboard.L90=U64EMPTY;
	depth=gamedepth=0;
	for(i=0;i<64;i++)
		if(toBit[i]&mainboard.AllPieces)
		{
			mainboard.R45|=toBitR45[i];
			mainboard.L45|=toBitL45[i];
			mainboard.L90|=toBitL90[i];
		}
	for(i=0;i<64;i++)
	{
		if(toBit[i]&mainboard.Pieces[P])
			mainboard.PieceTypes[i]=P;
		else if(toBit[i]&mainboard.Pieces[K])
			mainboard.PieceTypes[i]=K;
		else if(toBit[i]&mainboard.Pieces[N])
			mainboard.PieceTypes[i]=N;
		else if(toBit[i]&mainboard.Pieces[B])
			mainboard.PieceTypes[i]=B;
		else if(toBit[i]&mainboard.Pieces[R])
			mainboard.PieceTypes[i]=R;
		else if(toBit[i]&mainboard.Pieces[Q])
			mainboard.PieceTypes[i]=Q;
		else
			mainboard.PieceTypes[i]=EMPTY;
	}
	mainboard.material=signSide[mainboard.side]*(
		Pval*(popCount(piecesSide(mainboard,P))-popCount(piecesXSide(mainboard,P)))+
		Rval*(popCount(piecesSide(mainboard,R))-popCount(piecesXSide(mainboard,R)))+
		Bval*(popCount(piecesSide(mainboard,B))-popCount(piecesXSide(mainboard,B)))+
		Nval*(popCount(piecesSide(mainboard,N))-popCount(piecesXSide(mainboard,N)))+
		Qval*(popCount(piecesSide(mainboard,Q))-popCount(piecesXSide(mainboard,Q))));
	generatePieceSquare(&mainboard);
	generateLegalMoves(&mainboard,&mainMoveList);
	resetTT();
	resetHH();
	resetKillers();
	useBook=false;
}

/*setBoard()
 *sets the main board according to a FEN string
 *
 *@param FEN - a FEN string with the setboard command
 *
 *@returns true and prints Error Message if FEN is illegal
 */
bool setBoard(char* FEN)
{
	char temp[256], temp2, temp3[5], temp4[3], temp5[4], temp6[11];
	int i,j;
	nullBoard();
	sscanf(FEN,"setboard %s %c %s %s %s %s",temp,&temp2,temp3,temp4,temp5,temp6);
	//Parse Active Color
	if(temp2=='w')
		mainboard.side=WHITE;
	else if(temp2=='b')
		mainboard.side=BLACK;
	else
	{
		if(openedInConsole)
			printf("Error (invalid color field): %s",FEN);
		else
			printf("tellusererror Invalid Color Field\n");
		return true;
	}
	//Parse Castling
	mainboard.castling=0;
	if(*temp3=='-' || *temp3<0);
	else
	{
		for(i=0;i<4 && temp3[i]!='\0';i++)
		{
			switch(temp3[i])
			{
				case 'K': mainboard.castling^=WK; break;
				case 'k': mainboard.castling^=BK; break;
				case 'Q': mainboard.castling^=WQ; break;
				case 'q': mainboard.castling^=BQ; break;
				default:
				if(openedInConsole)
					printf("Error (invalid castling field): %d",temp3[i]);
				else
					printf("tellusererror Invalid Castling Field\n");
				return true;
			}
		}
	}
	//Parse EP Square
	mainboard.EP=U64EMPTY;
	if(temp4[0]>='a' && temp4[0]<='h' && temp4[1]>='1' && temp4[1]<='9')
		mainboard.EP=toBit[coordsToSquare(temp4[0], temp4[1])];
	//Parse Fifty
	mainboard.fifty=*temp6=0;
	if(*temp5!='-' && *temp5>='0' && *temp5 <='9')
		sscanf(temp5,"%d",temp6);
	if(*temp6*2>=0 && *temp6*2<=51)
		mainboard.fifty=*temp6*2;
	else
		mainboard.fifty=0;
	//Parse Initial Game Move Number
	if(*temp6=='-')
		initialMoveNumber=1;
	else
		sscanf(temp6,"%d",&initialMoveNumber);
	if(initialMoveNumber<=0) initialMoveNumber=1;
	//Parse Piece Placement Data
	strcat(temp,"/");
	i=56; j=0;
	while(i>=0 && j<256)
	{
		temp2=temp[j];
		if(temp2>='1' && temp2<='8')
		{
			i+=temp2-'0';
			j++;
			continue;
		}
		if(temp2=='/')
		{
			i-=16;
			j++;
			continue;
		}
		if(charToPiece(temp2)==EMPTY || i>=64)
		{
			if(openedInConsole)
				printf("Error (bad FEN): %s\n",FEN);
			else
				printf("tellusererror Bad FEN\n");
			return true;
		}
		addPiece(temp2>'a' && temp2<'z',charToPiece(temp2),i);
		i++;
		j++;
	}
	inferRestOfBoard();
	if(isIllegalPosition())
	{
		if(openedInConsole)
			printf("Error (Illegal Position): %s\n",FEN);
		return true;
	}
	if(openedInConsole)
		printf("Position Set Sucessfully\n");
	gameEnded();
	return false;
}

/*addPiece()
 *adds a piece to the board clearing the old one
 *
 *@param color - color of the piece
 *@param type - the piece type (number)
 */
void addPiece(bool color, char type, int square)
{
	if(color==NOSIDE || !type || square<0 || square>=64)
		return;
	clearSquare(square);
	mainboard.PiecesSide[color]^=toBit[square];
	mainboard.Pieces[type]^=toBit[square];
}

/*clearSquare()
 *makes a square empty
 *
 *@param square - the square to be cleared
 */
void clearSquare(int square)
{
	int i;
	if(square<0 || square>63)
		return;
	mainboard.PiecesSide[WHITE]&=~toBit[square];
	mainboard.PiecesSide[BLACK]&=~toBit[square];
	for(i=1; i<7; i++)
		mainboard.Pieces[i]&=~toBit[square];
}

/*changeColor()
 *changes the color of the current square regardless if it is empty or not
 *
 *@param square - an occupied square
 */
void changeColor(int square)
{
	mainboard.PiecesSide[WHITE]^=toBit[square];
	mainboard.PiecesSide[BLACK]^=toBit[square];
}

/*isIllegalPosition()
 *Determines whether the position is legal.
 *The position can be illegal, but it must be legal enough for the engine to
 *work without errors.  This function gives the telluser error command to the
 *Winboard interface but does not output anything when used in console. It
 *also updates castling privilages to make sure the match with the position.
 *
 *@returns true if the position is illegal
 */
bool isIllegalPosition()
{
	//check if the number of Kings on each side is ok
	if(popCount(piecesSide(mainboard,K))!=1 || popCount(piecesXSide(mainboard,K))!=1)
	{
		if(!openedInConsole)
			printf("tellusererror Illegal Position: Wrong number of kings.\n");
		return true;
	}
	//make sure the opposing side is not in check
	if(inCheck(mainboard,mainboard.xside))
	{
		if(!openedInConsole)
			printf("tellusererror Illegal Position: Opposite side in Check.\n");
		return true;
	}
	//make sure the ep square matches with an ep pawn
	if(mainboard.EP)
	{
		//if white just moved
		if(mainboard.side && !((mainboard.EP<<8)&(mainboard.PiecesSide[WHITE]&mainboard.Pieces[P])))
		{
			if(!openedInConsole)
				printf("tellusererror Illegal Position: Bad E.P. square\n");
			return true;
		}
		//if black just moved
		if(!((mainboard.EP>>8)&(mainboard.PiecesSide[BLACK]&mainboard.Pieces[P])))
		{
			if(!openedInConsole)
				printf("tellusererror Illegal Position: Bad E.P. square\n");
			return true;
		}
	}
	//edit castling legality if the king and rook positions are to the contrary
	if(hasCastlingPrivilages(mainboard,WHITE))
	{
		if(!(mainboard.Pieces[K]&mainboard.PiecesSide[WHITE]&toBit[4]))
			mainboard.castling&=notAllCastlingBitsSide[WHITE];
		else
		{
			if((mainboard.castling&WK) && !(mainboard.Pieces[R]&mainboard.PiecesSide[WHITE]&toBit[7]))
				mainboard.castling&=notCastlingBits[WHITE][KINGSIDE];
			if((mainboard.castling&WQ) && !(mainboard.Pieces[R]&mainboard.PiecesSide[WHITE]&toBit[0]))
				mainboard.castling&=notCastlingBits[WHITE][QUEENSIDE];
		}
	}
	if(hasCastlingPrivilages(mainboard,BLACK))
	{
		if(!(mainboard.Pieces[K]&mainboard.PiecesSide[BLACK]&toBit[56+4]))
			mainboard.castling&=notAllCastlingBitsSide[BLACK];
		else
		{
			if((mainboard.castling&BK) && !(mainboard.Pieces[R]&mainboard.PiecesSide[BLACK]&toBit[56+7]))
				mainboard.castling&=notCastlingBits[BLACK][KINGSIDE];
			if((mainboard.castling&BQ) && !(mainboard.Pieces[R]&mainboard.PiecesSide[BLACK]&toBit[56+0]))
				mainboard.castling&=notCastlingBits[BLACK][QUEENSIDE];
		}
	}
	return false;
}

/*makemove()
 *makes changes to the game board when a move is played; also stores the current
 *board position in searchHistory[depth] and then increments depth
 *
 *@param m - a pseudolegal move to be made
 *
 *@returns true if the move is illegal
 */
U64 makemove(board* pos, const move m)
{
	char to=extractTo(m), piece=extractPiece(m), capture=extractCapture(m),
			from=extractFrom(m) ,promotion=extractPromotion(m),
			special=extractSpecial(m);
	U64 temp=toBit[from]^toBit[to];
	pos->fifty++;

	if(pos->EP) //clear ep flag
	{
		pos->hashkey^=zobristEP[LastOne(pos->EP)];
		pos->EP=U64EMPTY;
	}
	//clear flags
	clearSearchFlags(pos->SF);

	if(m==NULLMOVE) //nullmove only made if pos->SF&0x8 is true
	{
		pos->hashkey=~pos->hashkey;
		pos->side=!pos->side;
		pos->xside=!pos->xside;
		pos->SF|=encodeSFNull;
		return false;
	}

	if(special)
	{
		if(piece==K) //castling
		{
			special>>=1;
			pos->hashkey^=zobristCastling[pos->side][special];
			pos->Pieces[K]^=castlingXors[pos->side][special][0];
			pos->Pieces[R]^=castlingXors[pos->side][special][1];
			pos->AllPieces^=castlingRotatedXors[pos->side][special][0];
			pos->L90^=castlingRotatedXors[pos->side][special][1];
			pos->L45^=castlingRotatedXors[pos->side][special][2];
			pos->R45^=castlingRotatedXors[pos->side][special][3];
			pos->PiecesSide[pos->side]^=castlingRotatedXors[pos->side][special][0];
			pos->PieceTypes[castlingSquaresK[pos->side][special][0]]=EMPTY;
			pos->PieceTypes[castlingSquaresK[pos->side][special][1]]=K;
			pos->PieceTypes[castlingSquaresR[pos->side][special][0]]=EMPTY;
			pos->PieceTypes[castlingSquaresR[pos->side][special][1]]=R;
			pos->castling&=notAllCastlingBitsSide[pos->side];
		}
		else //enpassant
		{
			pos->hashkey^=zobrist[pos->side][P][from]^zobrist[pos->side][P][to]^zobrist[pos->xside][P][pawnEPset[pos->side]+to];
			pos->Pieces[P]^=temp^toBit[pawnEPset[pos->side]+to];
			pos->AllPieces^=temp^toBit[pawnEPset[pos->side]+to];
			pos->L45^=toBitL45[from]^toBitL45[to]^toBitL45[pawnEPset[pos->side]+to];
			pos->R45^=toBitR45[from]^toBitR45[to]^toBitR45[pawnEPset[pos->side]+to];
			pos->L90^=toBitL90[from]^toBitL90[to]^toBitL90[pawnEPset[pos->side]+to];
			pos->PiecesSide[pos->side]^=temp;
			pos->PiecesSide[pos->xside]^=toBit[pawnEPset[pos->side]+to];
			pos->PieceTypes[pawnEPset[pos->side]+to]=pos->PieceTypes[from]=EMPTY;
			pos->PieceTypes[to]=P;
			pos->material+=signSide[pos->side]*Pval;
		}
		goto end;
	}
	if(piece==R) //adjust castling if rook moved
	{
		if(from==castlingQRookFrom[pos->side])
			pos->castling&=notCastlingBits[pos->side][QUEENSIDE];
		else if(from==castlingKRookFrom[pos->side])
			pos->castling&=notCastlingBits[pos->side][KINGSIDE];
	}
	else if(piece==K) //adjust castling if king moved
		pos->castling&=notAllCastlingBitsSide[pos->side];
	if(capture)
	{
		pos->SF^=encodeCapture(capture);
		if(capture==R)
		{
			if(to==castlingSquaresR[pos->xside][KINGSIDE][0])
				pos->castling&=notCastlingBits[pos->xside][KINGSIDE];
			else if(to==castlingSquaresR[pos->xside][QUEENSIDE][0])
				pos->castling&=notCastlingBits[pos->xside][QUEENSIDE];
		}
		pos->fifty=0;
		pos->hashkey^=zobrist[pos->xside][capture][to]^zobrist[pos->side][piece][from]^zobrist[pos->side][piece][to];
		pos->PiecesSide[pos->xside]^=toBit[to];
		pos->Pieces[piece]^=temp;
		pos->Pieces[capture]^=toBit[to];
		pos->AllPieces^=toBit[from];
		pos->L45^=toBitL45[from];
		pos->R45^=toBitR45[from];
		pos->L90^=toBitL90[from];
		pos->PiecesSide[pos->side]^=temp;
		pos->PieceTypes[from]=EMPTY;
		pos->PieceTypes[to]=piece;
		pos->material+=signSide[pos->side]*PieceVal[capture];
	}
	else
	{
		pos->hashkey^=zobrist[pos->side][piece][from]^zobrist[pos->side][piece][to];
		pos->Pieces[piece]^=temp;
		pos->AllPieces^=temp;
		pos->L45^=toBitL45[from]^toBitL45[to];
		pos->R45^=toBitR45[from]^toBitR45[to];
		pos->L90^=toBitL90[from]^toBitL90[to];
		pos->PiecesSide[pos->side]^=temp;
		pos->PieceTypes[from]=EMPTY;
		pos->PieceTypes[to]=piece;
	}
	if(piece==P)
	{
		pos->fifty=0;
		if(promotion)
		{
			pos->hashkey^=zobrist[pos->side][P][to]^zobrist[pos->side][promotion][to];
			pos->PieceTypes[to]=promotion;
			pos->Pieces[P]^=toBit[to];
			pos->Pieces[promotion]^=toBit[to];
			pos->material+=signSide[pos->side]*(PieceVal[promotion]-Pval);
		}
		else if((to-from)==doubleMove[pos->side] && Pcaps[pos->side][to+pawnEPset[pos->side]]&piecesXSide(*pos,P))
		{
			pos->EP=toBit[from=to+pawnEPset[pos->side]];
			pos->hashkey^=zobristEP[from];
		}
	}
end:
	pos->hashkey=~pos->hashkey;
	pos->side=!pos->side;
	pos->xside=!pos->xside;
	return inCheck(*pos,pos->xside);
}

/*makeGameMove()
 *makes a game move by calling makemove and updating game variables
 *
 *@param m-the move to sbe made
 *
 *@returns "U64 true" if the move is illegal
 */
U64 makeGameMove(const move m)
{
	U64 x;
	if(gamedepth==MAX_GAMELENGTH-1)
	{
		initialMoveNumber+=gamedepth/2;
		gamedepth=0;
	}
	gameHistory[gamedepth++]=mainboard;
	x=makemove(&mainboard,m);
	depth=0;
	generatePieceSquare(&mainboard);
	generateLegalMoves(&mainboard,&mainMoveList);
	gameEnded(); //print something if the game ended
	return x;
}

/*makeGameTakeback()
 *reverts the game board to the position where the last game move was made
 *
 *@returns true if the takeback could not be made
 */
bool makeGameTakeback()
{
	if(gamedepth==0)
		return false;
	mainboard=gameHistory[--gamedepth];
	depth=0;
	generatePieceSquare(&mainboard);
	generateLegalMoves(&mainboard,&mainMoveList);
	//resetTT();
	return true;
}

/*gameEnded()
 *checks the current board position to see if the game has ended
 *prints something if it has and sets the engine side to no-side
 *
 *returns true if the game has ended
 */
bool gameEnded()
{
	int d, count;
	int BishopsSide, KnightsSide, BishopsXSide, KnightsXSide;
	//checkmate and stalemate
	if(mainMoveList.moveCount==0)
	{
		if(inCheck(mainboard,mainboard.side))
			printf("%s {%s mates}\n",winToStr[mainboard.xside],sideToStr[mainboard.xside]);
		else
		{
			printf("offer draw\n");
			printf("1/2-1/2 {Stalemate}\n");
		}
		compside=NOSIDE;
		return true;
	}
	//fifty-move rule
	if(mainboard.fifty>=100)
	{
		printf("offer draw\n");
		printf("1/2-1/2 {fifty move}\n");
		compside=NOSIDE;
		return true;
	}
	//3 move repetetion
	count=0;
	for(d=gamedepth-1;d>=0 && d>=gamedepth-mainboard.fifty;d--)
	{
		if(gameHistory[d].hashkey==mainboard.hashkey)
			count++;
		if(count==2)
		{
			printf("offer draw\n");
			printf("1/2-1/2 {3 fold repetition}\n");
			compside=NOSIDE;
			return true;
		}
	}
	//simple insufficient material detection - dosen't care about bishop square colors
	//make sure there are no pawns, queens or rooks
	if(mainboard.AllPieces!=U64EMPTY && !popCount(mainboard.Pieces[R]|mainboard.Pieces[Q]|mainboard.Pieces[P]))
	{
		BishopsSide=BishopsXSide=0;
		if(piecesSide(mainboard,B)&WHITESQUARES)
			BishopsSide++;
		if(piecesSide(mainboard,B)&BLACKSQUARES)
			BishopsSide++;
		if(piecesXSide(mainboard,B)&WHITESQUARES)
			BishopsXSide++;
		if(piecesXSide(mainboard,B)&BLACKSQUARES)
			BishopsXSide++;
		KnightsSide=popCount(piecesSide(mainboard,N));
		KnightsXSide=popCount(piecesXSide(mainboard,N));
		//if there are both knights and bishops on one side
		if((BishopsSide>0 && KnightsSide>0) || (BishopsXSide>0 && KnightsXSide>0))
			return false;
		//if there are atleast 2 bishops on either side
		if(BishopsSide>=2 || BishopsXSide>=2)
			return false;
		//if there are atleast 2 knights on either side
		if(KnightsSide>=2 || KnightsXSide>=2)
			return false;
		printf("offer draw\n");
		printf("1/2-1/2 {insufficient material}\n");
		compside=NOSIDE;
		return true;
	}
	return false;
}

/*isPinnedtoK()
 *tells you whether a piece is pinned to king or not
 *this function is a little bit slow, do not use in search
 *
 *@param pos       - the board position
 *@param square    - the square to be tested if pinned
 */
bool isPinnedToK(const board* pos, char square)
{
	char kingpos,raycast;
	U64 attackers;
	bool side;
	//figure out the kingpos
	if(!(pos->AllPieces&toBit[square]))
		return false;
	if(pos->PiecesSide[pos->side]&toBit[square])
	{
		side=pos->side;
		kingpos=LastOne(piecesSide(*pos,K));
		if(isDiagonal(kingpos,square))
		{
			if(!(Bmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesXSide(*pos,Q)|piecesXSide(*pos,B);
		}
		else
		{
			if(!(Rmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesXSide(*pos,Q)|piecesXSide(*pos,R);
		}
	}
	else
	{
		side=pos->xside;
		kingpos=LastOne(piecesXSide(*pos,K));
		if(isDiagonal(kingpos,square))
		{
			if(!(Bmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesSide(*pos,Q)|piecesXSide(*pos,B);
		}
		else
		{
			if(!(Rmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesSide(*pos,Q)|piecesXSide(*pos,R);
		}
	}
	//cast the ray to find pinning pieces
	raycast=SEEdir[square][kingpos][(*occupancy[square][kingpos])(pos,square)];
	if(raycast>=0 && toBit[raycast]&attackers)
		return true;
	return false;
}

/*isDirPinnedtoK()
 *tells you whether a piece is directionally pinned to king or not
 *this function is a little bit slow, do not use in search
 *
 *@param pos       - the board position
 *@param square    - the square to be tested if pinned
 *@param dirsq     - the direction square (where the piece wants to move to)
 */
bool isDirPinnedToK(const board* pos, char square, char dirsq)
{
	char kingpos,raycast;
	U64 attackers;
	bool side;
	//figure out the kingpos
	if(!(pos->AllPieces&toBit[square]))
		return false;
	if(pos->PiecesSide[pos->side]&toBit[square])
	{
		side=pos->side;
		kingpos=LastOne(piecesSide(*pos,K));
		if(isDiagonal(kingpos,square))
		{
			if(!(Bmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesXSide(*pos,Q)|piecesXSide(*pos,B);
		}
		else
		{
			if(!(Rmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesXSide(*pos,Q)|piecesXSide(*pos,R);
		}
	}
	else
	{
		side=pos->xside;
		kingpos=LastOne(piecesXSide(*pos,K));
		if(isDiagonal(kingpos,square))
		{
			if(!(Bmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesSide(*pos,Q)|piecesXSide(*pos,B);
		}
		else
		{
			if(!(Rmoves(*pos,kingpos) & toBit[square])) return false;
			attackers=piecesSide(*pos,Q)|piecesXSide(*pos,R);
		}
	}
	//cast the ray to find pinning pieces
	raycast=SEEdir[square][kingpos][(*occupancy[square][kingpos])(pos,square)];
	/*printf("SEEdir[%d][%d][0x%X]\n",square,kingpos,(*occupancy[square][kingpos])(pos,square));
	printf("raycast=%d\n",raycast);
	printBitBoard("attackers",attackers);*/
	if(raycast>=0 && toBit[raycast]&attackers)
	{
		//check if to square is on the raycast
		if(toBit[raycast]&ray[square][dirsq][(*occupancy[square][kingpos])(pos,square)])
			return false;
		return true;
	}
	return false;
}
